#include <string>
#include <fstream>

#include "framebuffer.h"

void FrameBuffer::setSize( unsigned int x, unsigned int y ) {
    delete image;
    image = new Color[ x * y ];
}

void FrameBuffer::clear( const Color & color ) {
    for ( unsigned int i = 0; i < x * y; i++ )
        image[i] = color;
}

void FrameBuffer::clear( float r, float g, float b ) {
    for ( unsigned int i = 0; i < x * y; i++ )
        image[i] = Color( r, g, b );
}

void FrameBuffer::writeBitmap( std::string filename ) const {
    struct bmpfile_magic { unsigned char m1; unsigned char m2; } bmpmagic = { 'B', 'M' };

    unsigned int bmpRowSize = 24 * x;
    bmpRowSize += ( bmpRowSize % 32  == 0 ) ? 0 : 32 - bmpRowSize % 32;

    struct bmpfile_header {
        unsigned long filesz : 32;
        unsigned long creator1 : 16;
        unsigned long creator2 : 16;
        unsigned long bmp_offset : 32;
    } fileheader = { 54 + bmpRowSize * y, 0, 0, 54 };

    struct {
        unsigned long header_sz : 32;
        long width : 32;
        long height : 32;
        unsigned long nplanes : 16;
        unsigned long bitspp : 16;
        unsigned long compress_type : 32;
        unsigned long bmp_bytesz : 32;
        long hres : 32;
        long vres : 32;
        unsigned long ncolors : 32;
        unsigned long nimpcolors : 32;
    } infoheader = { 40, x, y, 1, 24, 0, bmpRowSize * y, 2853, 2853, 0, 0 };

    unsigned char * bmpData = new unsigned char [ bmpRowSize / 8 * y ];

    for( unsigned int i = 0; i < y; i++ ) {
        for( unsigned int j = 0; j < x; j++ ) {
            bmpData[ i * bmpRowSize / 8 + j * 3 + 0 ] = 255 * image[ i * x + j ].blue();
            bmpData[ i * bmpRowSize / 8 + j * 3 + 1 ] = 255 * image[ i * x + j ].green();
            bmpData[ i * bmpRowSize / 8 + j * 3 + 2 ] = 255 * image[ i * x + j ].red();
        }
    }

    std::ofstream out( filename.c_str(), std::ios::out | std::ios::binary );
    out.write( reinterpret_cast<char *>( &bmpmagic ), sizeof( bmpmagic ) );
    out.write( reinterpret_cast<char *>( &fileheader ), sizeof( fileheader ) );
    out.write( reinterpret_cast<char *>( &infoheader ), sizeof( infoheader ) );
    out.write( reinterpret_cast<char *>( bmpData ), bmpRowSize / 8 * y );
    out.close();

    delete bmpData;
}
